package com.apobates.jforum.grief.aurl.convertor;

import com.apobates.jforum.grief.aurl.core.AUrlMeta;
import com.apobates.jforum.grief.aurl.spring.StringUtils;
import java.net.URI;
import java.net.URISyntaxException;

/**
 * URI的转换器
 */
public class URIConvertor implements AUrlMetaConvertor<URI> {
    private final boolean encode;

    public URIConvertor(boolean encode) {
        this.encode = encode;
    }

    @Override
    public URI convert(AUrlMeta aUrlMeta) throws IllegalStateException{
        URIConvertor.EncodeState encodeState = encode ? URIConvertor.EncodeState.FULLY_ENCODED : URIConvertor.EncodeState.RAW;
        try {
            if (encodeState.isEncoded()) {
                return new URI(new URIStringConvertor().convert(aUrlMeta));
            }
            else {
                String path = aUrlMeta.getPath();
                if (StringUtils.hasLength(path) && path.charAt(0) != _PATH_DELIMITER) {
                    // Only prefix the path delimiter if something exists before it
                    if (aUrlMeta.getScheme() != null || aUrlMeta.getUserInfo() != null || aUrlMeta.getHost() != null || AUrlMetaConvertor.isAppendPort(aUrlMeta.getPort())) {
                        path = _PATH_DELIMITER + path;
                    }
                }
                return new URI(
                        aUrlMeta.getScheme(),
                        aUrlMeta.getUserInfo(),
                        aUrlMeta.getHost(),
                        AUrlMetaConvertor.isAppendPort(aUrlMeta.getPort())?Integer.valueOf(aUrlMeta.getPort()):-1,
                        path,
                        aUrlMeta.getQuery(),
                        aUrlMeta.getFragment());
            }
        }
        catch (URISyntaxException ex) {
            throw new IllegalStateException("Could not create URI object: " + ex.getMessage(), ex);
        }
    }

    private enum EncodeState {

        /**
         * Not encoded.
         */
        RAW,

        /**
         * URI vars expanded first and then each URI component encoded by
         * quoting only illegal characters within that URI component.
         */
        FULLY_ENCODED,

        /**
         * URI template encoded first by quoting illegal characters only, and
         * then URI vars encoded more strictly when expanded, by quoting both
         * illegal chars and chars with reserved meaning.
         */
        TEMPLATE_ENCODED;


        public boolean isEncoded() {
            return this.equals(FULLY_ENCODED) || this.equals(TEMPLATE_ENCODED);
        }
    }
}
